WOLF core
WOLF: A Modular Estimation Framework for Robotics
XXXXXXXXXXXXXXXXXXXXXXXXvoid(0)" frameborder="0" name="MSearchResults" id="MSearchResults">
SE2.h
Go to the documentation of this file.
1// WOLF - Copyright (C) 2020-2026
2// Institut de Robòtica i Informàtica Industrial, CSIC-UPC.
3// Authors: Joan Solà Ortega (jsola@iri.upc.edu) and
4// Joan Vallvé Navarro (jvallve@iri.upc.edu)
5// All rights reserved.
6//
7// This file is part of WOLF: http://www.iri.upc.edu/wolf
8// WOLF is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License version 3
10// as published by the Free Software Foundation.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19#pragma once
20
21#include "core/common/wolf.h"
22#include "core/math/rotations.h"
24
25#include <Eigen/Geometry>
26#include <Eigen/Dense>
27
28/*
29 * The functions in this file are related to manipulations of Delta motion magnitudes used in 2d motion.
30 *
31 * The Delta is defined as a simple 2d pose with the rotation expressed as an angle,
32 * Delta = [Dp, Do]
33 * with
34 * Dp : position delta
35 * Do : angle delta (always in (-pi, pi])
36 * and its tangent vector (Lie algebra) is tau = [rho, theta].
37 *
38 * The functions are listed below:
39 *
40 * - identity: I = Delta at the origin, with Dp = [0,0]; Do = 0, so that D (+) I = I (+) D = D
41 * - inverse: so that D (+) D.inv = D.inv (+) D = I
42 * - compose: Dc = D1 (+) D2
43 * - between: Db = D2 (-) D1 := D1.inv (+) D2, so that D2 = D1 (+) Db
44 * - exp: go from tangent space to delta manifold (SE(2) exponential map)
45 * - log: go from delta manifold to tangent space (SE(2) logarithmic map)
46 * - plus: block-wise: D2 = [Dp1 + dp, Do1 + do]
47 * - minus: block-wise: d = [Dp2 - Dp1, Do2 - Do1], so that D2 = plus(D1, d)
48 * - interpolate: D = D1 (+) exp( t * log( D1.inv (+) D2 ) )
49 * - toSE2: 3x3 homogeneous matrix
50 * - jac_SE2_left, jac_SE2_right, jac_SE2_left_inv, jac_SE2_right_inv: Jacobians of SE(2)
51 *
52 * Each function is provided (when applicable) with the following APIs:
53 * - by parts, with the rotation as a scalar angle
54 * - by parts, with the rotation as a vector (1-vector with the angle)
55 * - full 3-vector [p, o] as output parameter and as return value
56 * - full 3-vector with Jacobians. Jacobians are block-wise: w.r.t. perturbations [dp, do] with additive dp
57 * and do, i.e. consistent with plus() and minus().
58 * - VectorComposite with keys 'P' and 'O', as output parameter and as return value
59 *
60 * ------------------------------------------------------------------------------------------
61 *
62 * Some of the functions below are based on:
63 *
64 * [1] J. Sola et. al. "A micro Lie theory for state estimation in robotics", tech rep. IRI 2018,
65 * https://arxiv.org/pdf/1812.01537.pdf
66 */
67
68namespace wolf
69{
70namespace SO2
71{
72using namespace Eigen;
73
74template <typename T>
75inline Matrix<T, 2, 2> exp(const T theta)
76{
77 return Rotation2D<T>(theta).matrix();
78}
79
80} // namespace SO2
81
82namespace SE2
83{
84using namespace Eigen;
85
86template <class T>
87inline Matrix<T, 2, 2> skew(const T& t)
88{
89 return (Matrix<T, 2, 2>() << (T)0, -t, t, (T)0).finished();
90}
91
94template <class D>
95inline Matrix<typename D::Scalar, 2, 1> skewed(const MatrixBase<D>& t)
96{
97 return Matrix<typename D::Scalar, 2, 1>(-t(1), t(0));
98}
99
102template <typename T>
103inline Matrix<T, 2, 2> V_helper(const T theta)
104{
105 using std::abs;
106 T s; // sin(theta) / theta
107 T c_1; // (1-cos(theta)) / theta
108
109 if (abs(theta) > T(Constants::EPS))
110 {
111 // [1] eq. 158, with 1 - cos(theta) = 2 sin^2(theta/2) (numerically stable)
112 T sin_half = sin(theta / T(2.0));
113 s = sin(theta) / theta;
114 c_1 = T(2.0) * sin_half * sin_half / theta;
115 }
116 else
117 {
118 // approx of [1] eq. 158
119 s = T(1.0) - theta * theta / T(6.0); // sin(x) ~= x - x^3/6
120 c_1 = theta / T(2.0); // cos(x) ~= 1 - x^2/2
121 }
122
123 return (Matrix<T, 2, 2>() << s, -c_1, c_1, s).finished();
124}
125
128template <typename T>
129inline Matrix<T, 2, 2> V_inv_helper(const T theta)
130{
131 using std::abs;
132 T a; // theta * sin(theta) / (2 * (1 - cos(theta))) = (theta / 2) / tan(theta / 2)
133
134 if (abs(theta) > T(Constants::EPS))
135 a = (theta / T(2.0)) / tan(theta / T(2.0));
136 else
137 a = T(1.0) - theta * theta / T(12.0);
138
139 return (Matrix<T, 2, 2>() << a, theta / T(2.0), -theta / T(2.0), a).finished();
140}
141
144template <class D, typename T>
145inline Matrix<T, 2, 1> J_Vp_theta(const MatrixBase<D>& p, const T theta)
146{
148
149 /* Jacobian of t = V(theta)*p wrt theta, with V = [s, -c_1; c_1, s]:
150 * dV/dtheta = [ds, -dc_1; dc_1, ds]
151 * ds = d(sin(theta)/theta)/dtheta = (theta cos(theta) - sin(theta)) / theta^2
152 * dc_1 = d((1-cos(theta))/theta)/dtheta = (theta sin(theta) - 1 + cos(theta)) / theta^2
153 * (Taylor series for small angles, where the closed forms are numerically unstable)
154 */
155 using std::abs;
156 T ds, dc_1;
157 if (abs(theta) > T(1e-2))
158 {
159 T s_th = sin(theta);
160 T c_th = cos(theta);
161 T theta2 = theta * theta;
162 ds = (theta * c_th - s_th) / theta2;
163 dc_1 = (theta * s_th - T(1.0) + c_th) / theta2;
164 }
165 else
166 {
167 T theta2 = theta * theta;
168 ds = theta * (-T(1. / 3.) + theta2 * (T(1. / 30.) - theta2 / T(840.)));
169 dc_1 = T(0.5) + theta2 * (-T(1. / 8.) + theta2 * (T(1. / 144.) - theta2 / T(5760.)));
170 }
171
172 return Matrix<T, 2, 1>(ds * p(0) - dc_1 * p(1), dc_1 * p(0) + ds * p(1));
173}
174
176// JACOBIANS OF SE(2)
177
180template <typename D>
181inline Matrix<typename D::Scalar, 3, 3> jac_SE2_left(const MatrixBase<D>& tangent)
182{
184 typedef typename D::Scalar T;
185
186 T x = tangent(0);
187 T y = tangent(1);
188 T theta = tangent(2);
189
190 /* third column: [x B + y A, -x A + y B] with
191 * A = (1 - cos(theta)) / theta^2
192 * B = (theta - sin(theta)) / theta^2
193 * (Taylor series for small angles, where the closed forms are numerically unstable)
194 */
195 using std::abs;
196 T A, B;
197 if (abs(theta) > T(1e-2))
198 {
199 T sin_half = sin(theta / T(2.0));
200 T theta2 = theta * theta;
201 A = T(2.0) * sin_half * sin_half / theta2;
202 B = (theta - sin(theta)) / theta2;
203 }
204 else
205 {
206 T theta2 = theta * theta;
207 A = T(0.5) + theta2 * (-T(1. / 24.) + theta2 / T(720.));
208 B = theta * (T(1. / 6.) + theta2 * (-T(1. / 120.) + theta2 / T(5040.)));
209 }
210
211 Matrix<T, 3, 3> Jl;
212 Jl.template topLeftCorner<2, 2>() = V_helper(theta);
213 Jl(0, 2) = x * B + y * A;
214 Jl(1, 2) = -x * A + y * B;
215 Jl(2, 0) = T(0);
216 Jl(2, 1) = T(0);
217 Jl(2, 2) = T(1);
218 return Jl;
219}
220
223template <typename D>
224inline Matrix<typename D::Scalar, 3, 3> jac_SE2_right(const MatrixBase<D>& tangent)
225{
226 return jac_SE2_left(Matrix<typename D::Scalar, 3, 1>(-tangent));
227}
228
231template <typename D>
232inline Matrix<typename D::Scalar, 3, 3> jac_SE2_left_inv(const MatrixBase<D>& tangent)
233{
234 typedef typename D::Scalar T;
235
236 // Jl = [A, b; 0, 1] --> Jl.inv = [A.inv, -A.inv * b; 0, 1]
237 Matrix<T, 3, 3> Jl = jac_SE2_left(tangent);
238 Matrix<T, 2, 2> A_inv = V_inv_helper(T(tangent(2)));
239 Matrix<T, 3, 3> Jl_inv = Matrix<T, 3, 3>::Identity();
240 Jl_inv.template topLeftCorner<2, 2>() = A_inv;
241 Jl_inv.template topRightCorner<2, 1>() = -A_inv * Jl.template topRightCorner<2, 1>();
242 return Jl_inv;
243}
244
247template <typename D>
248inline Matrix<typename D::Scalar, 3, 3> jac_SE2_right_inv(const MatrixBase<D>& tangent)
249{
250 return jac_SE2_left_inv(Matrix<typename D::Scalar, 3, 1>(-tangent));
251}
252
254// IDENTITY
255
256template <typename D>
257inline void identity(MatrixBase<D>& p, typename D::Scalar& o)
258{
260 p.setZero();
261 o = typename D::Scalar(0);
262}
263
264template <typename D1, typename D2>
265inline void identity(MatrixBase<D1>& p, MatrixBase<D2>& o)
266{
268 identity(p, o(0));
269}
270
271template <typename D>
272inline void identity(MatrixBase<D>& d)
273{
275
276 Map<Matrix<typename D::Scalar, 2, 1>> p(&d(0));
277 identity(p, d(2));
278}
279
280template <typename T = double>
281inline Matrix<T, 3, 1> identity()
282{
283 Matrix<T, 3, 1> ret;
284 identity(ret);
285 return ret;
286}
287
289{
290 v.clear();
291 v['P'].resize(2);
292 v['O'].resize(1);
293 identity(v['P'], v['O']);
294}
295
297{
299 identity(v);
300 return v;
301}
302
304// INVERSE
305
306template <typename D1, typename D2>
307inline void inverse(const MatrixBase<D1>& p, const typename D1::Scalar& o, MatrixBase<D2>& ip, typename D2::Scalar& io)
308{
311
312 ip = SO2::exp(-o) * -p;
313 io = pi2pi(-o);
314}
315
316template <typename D1, typename D2, typename D3, typename D4>
317inline void inverse(const MatrixBase<D1>& p, const MatrixBase<D2>& o, MatrixBase<D3>& ip, MatrixBase<D4>& io)
318{
321
322 inverse(p, o(0), ip, io(0));
323}
324
325template <typename D1, typename D2>
326inline void inverse(const MatrixBase<D1>& d, MatrixBase<D2>& id)
327{
330
331 const auto p = d.template head<2>();
332 Map<Matrix<typename D2::Scalar, 2, 1>> ip(&id(0));
333
334 inverse(p, d(2), ip, id(2));
335}
336
337template <typename D>
338inline Matrix<typename D::Scalar, 3, 1> inverse(const MatrixBase<D>& d)
339{
340 Matrix<typename D::Scalar, 3, 1> id;
341 inverse(d, id);
342 return id;
343}
344
345inline void inverse(const VectorComposite& v, VectorComposite& c)
346{
347 c['P'].resize(2);
348 c['O'].resize(1);
349 inverse(v.at('P'), v.at('O'), c['P'], c['O']);
350}
351
353{
355 inverse(v, c);
356 return c;
357}
358
360// COMPOSE
361
362template <typename D1, typename D2, typename D3>
363inline void compose(const MatrixBase<D1>& p1,
364 const typename D1::Scalar& o1,
365 const MatrixBase<D2>& p2,
366 const typename D2::Scalar& o2,
367 MatrixBase<D3>& pc,
368 typename D3::Scalar& oc)
369{
373
374 // tc = t1 + R1 t2
375 pc = p1 + SO2::exp(o1) * p2;
376
377 // Rc = R1 R2 --> theta = theta1 + theta2
378 oc = pi2pi(o1 + o2);
379}
380
381template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
382inline void compose(const MatrixBase<D1>& p1,
383 const MatrixBase<D2>& o1,
384 const MatrixBase<D4>& p2,
385 const MatrixBase<D5>& o2,
386 MatrixBase<D7>& pc,
387 MatrixBase<D8>& oc)
388{
392
393 compose(p1, o1(0), p2, o2(0), pc, oc(0));
394}
395
396template <class D1, class D2, class D3>
397inline void compose(const MatrixBase<D1>& _delta1,
398 const MatrixBase<D2>& _delta2,
399 MatrixBase<D3>& _delta1_compose_delta2)
400{
403 MatrixSizeCheck<3, 1>::check(_delta1_compose_delta2);
404
405 const auto p1 = _delta1.template head<2>();
406 const auto p2 = _delta2.template head<2>();
407 Map<Matrix<typename D3::Scalar, 2, 1>> pc(&_delta1_compose_delta2(0));
408
409 compose(p1, _delta1(2), p2, _delta2(2), pc, _delta1_compose_delta2(2));
410}
411
412template <class D1, class D2>
413inline Matrix<typename D1::Scalar, 3, 1> compose(const MatrixBase<D1>& _delta1, const MatrixBase<D2>& _delta2)
414{
415 Matrix<typename D1::Scalar, 3, 1> delta1_compose_delta2;
416 compose(_delta1, _delta2, delta1_compose_delta2);
417 return delta1_compose_delta2;
418}
419
420template <class D1, class D2, class D3, class D4, class D5>
421inline void compose(const MatrixBase<D1>& _delta1,
422 const MatrixBase<D2>& _delta2,
423 MatrixBase<D3>& _delta1_compose_delta2,
424 MatrixBase<D4>& _J_compose_delta1,
425 MatrixBase<D5>& _J_compose_delta2)
426{
429 MatrixSizeCheck<3, 1>::check(_delta1_compose_delta2);
430 MatrixSizeCheck<3, 3>::check(_J_compose_delta1);
431 MatrixSizeCheck<3, 3>::check(_J_compose_delta2);
432
433 typedef typename D1::Scalar T;
434
435 Matrix<T, 2, 2> R1 = SO2::exp(T(_delta1(2))); // need temporary
436
437 /* Jacobians in composite form [1] see eqs. (89, 125, 129, 130)
438 *
439 * resulting delta is:
440 *
441 * tc = t1 + R1 t2 (*)
442 * Rc = R1 R2 (**)
443 *
444 * Jacobians have the form:
445 *
446 * [ J_t_t J_t_R ]
447 * [ J_r_t J_R_R ]
448 *
449 * Jacobian blocks are:
450 *
451 * J_tc_t1 = I trivial from (*)
452 * J_tc_R1 = R1 [1]x t2 = R1 (-t2.y ; t2.x) see [1]: eq. (129)
453 *
454 * J_Rc_t1 = (0 0) trivial from (**)
455 * J_Rc_R1 = 1 see [1]: eq. (125)
456 *
457 * J_tc_t2 = R1 see [1]: eq. (130)
458 * J_tc_R2 = 0 trivial from (*)
459 *
460 * J_Rc_t2 = 0 trivial from (**)
461 * J_Rc_R2 = 1 see [1]: eq. (125)
462 */
463
464 _J_compose_delta1.setIdentity();
465 _J_compose_delta1.template block<2, 1>(0, 2) = R1 * skewed(_delta2.template head<2>());
466
467 _J_compose_delta2.setIdentity(3, 3);
468 _J_compose_delta2.template block<2, 2>(0, 0) = R1;
469
470 // compose deltas -- done here to avoid aliasing when calling with input `_delta1` and result referencing the same
471 // variable
472 compose(_delta1, _delta2, _delta1_compose_delta2);
473}
474
475inline void compose(const VectorComposite& _x1, const VectorComposite& _x2, VectorComposite& _c)
476{
477 _c['P'].resize(2);
478 _c['O'].resize(1);
479 compose(_x1.at('P'), _x1.at('O'), _x2.at('P'), _x2.at('O'), _c['P'], _c['O']);
480}
481
483{
485 compose(x1, x2, c);
486 return c;
487}
488
489// inline void compose(const VectorComposite& _x1,
490// const VectorComposite& _x2,
491// VectorComposite& _c,
492// MatrixComposite& _J_c_x1,
493// MatrixComposite& _J_c_x2)
494// {
495// const auto& p1 = _x1.at('P');
496// const auto& a1 = _x1.at('O')(0); // angle
497// Matrix2d R1 = SO2::exp(a1); // need temporary
498
499// const auto& p2 = _x2.at('P');
500// const auto& a2 = _x2.at('O')(0); // angle
501
502// /* Jacobians in composite form [1] see eqs. (89, 125, 129, 130)
503// * (see compose() above)
504// */
505
506// _J_c_x1.clear();
507// _J_c_x1.emplace('P', 'P', Matrix2d::Identity());
508// _J_c_x1.emplace('P', 'O', MatrixXd(R1 * skewed(p2)));
509// _J_c_x1.emplace('O', 'P', RowVector2d(0, 0));
510// _J_c_x1.emplace('O', 'O', Matrix1d(1));
511
512// _J_c_x2.clear();
513// _J_c_x2.emplace('P', 'P', R1);
514// _J_c_x2.emplace('P', 'O', Vector2d(0, 0));
515// _J_c_x2.emplace('O', 'P', RowVector2d(0, 0));
516// _J_c_x2.emplace('O', 'O', Matrix1d(1));
517
518// // Actually compose the vectors here. This avoids aliasing in case this is called with 'c' coinciding with 'x1'
519// or
520// // 'x2'.
521
522// // tc = t1 + R1 t2
523// _c['P'] = p1 + R1 * p2;
524
525// // Rc = R1 R2 --> theta = theta1 + theta2
526// _c['O'] = Matrix1d(pi2pi(a1 + a2));
527// }
528
530// BETWEEN
531
532template <typename D1, typename D2, typename D3>
533inline void between(const MatrixBase<D1>& p1,
534 const typename D1::Scalar& o1,
535 const MatrixBase<D2>& p2,
536 const typename D2::Scalar& o2,
537 MatrixBase<D3>& p12,
538 typename D3::Scalar& o12)
539{
543
544 p12 = SO2::exp(-o1) * (p2 - p1);
545 o12 = pi2pi(o2 - o1);
546}
547
548template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
549inline void between(const MatrixBase<D1>& p1,
550 const MatrixBase<D2>& o1,
551 const MatrixBase<D4>& p2,
552 const MatrixBase<D5>& o2,
553 MatrixBase<D7>& p12,
554 MatrixBase<D8>& o12)
555{
559
560 between(p1, o1(0), p2, o2(0), p12, o12(0));
561}
562
563template <typename D1, typename D2, typename D3>
564inline void between(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& d12)
565{
569
570 const auto p1 = d1.template head<2>();
571 const auto p2 = d2.template head<2>();
572 Map<Matrix<typename D3::Scalar, 2, 1>> p12(&d12(0));
573
574 between(p1, d1(2), p2, d2(2), p12, d12(2));
575}
576
577template <typename D1, typename D2>
578inline Matrix<typename D1::Scalar, 3, 1> between(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
579{
580 Matrix<typename D1::Scalar, 3, 1> d12;
581 between(d1, d2, d12);
582 return d12;
583}
584
585inline void between(const VectorComposite& x1, const VectorComposite& x2, VectorComposite& x12)
586{
587 x12['P'].resize(2);
588 x12['O'].resize(1);
589 between(x1.at('P'), x1.at('O'), x2.at('P'), x2.at('O'), x12['P'], x12['O']);
590}
591
593{
594 VectorComposite x12;
595 between(x1, x2, x12);
596 return x12;
597}
598
600// EXP
601
602template <typename D1, typename D2>
603inline void exp(const MatrixBase<D1>& rho, const typename D1::Scalar& theta, MatrixBase<D2>& p, typename D2::Scalar& o)
604{
607
608 // [1] eq. 156
609 p = V_helper(theta) * rho;
610 o = pi2pi(theta);
611}
612
613template <typename D1, typename D2, typename D3, typename D4>
614inline void exp(const MatrixBase<D1>& rho, const MatrixBase<D2>& theta, MatrixBase<D3>& p, MatrixBase<D4>& o)
615{
618
619 exp(rho, theta(0), p, o(0));
620}
621
622template <class D1, class D2>
623inline void exp(const MatrixBase<D1>& _tau, MatrixBase<D2>& _delta)
624{
627
628 const auto rho = _tau.template head<2>();
629 Map<Matrix<typename D2::Scalar, 2, 1>> p(&_delta(0));
630
631 exp(rho, _tau(2), p, _delta(2));
632}
633
634template <typename D>
635inline Matrix<typename D::Scalar, 3, 1> exp(const MatrixBase<D>& _tau)
636{
637 Matrix<typename D::Scalar, 3, 1> _delta;
638 exp(_tau, _delta);
639 return _delta;
640}
641
642template <class D1, class D2, class D3>
643inline void exp(const MatrixBase<D1>& _tau, MatrixBase<D2>& _delta, MatrixBase<D3>& _J_delta_tau)
644{
647 MatrixSizeCheck<3, 3>::check(_J_delta_tau);
648
649 typedef typename D1::Scalar T;
650
651 Matrix<T, 3, 1> tau = _tau; // copy (tau and delta may alias)
652
653 // Jacobian is the composite definition [1] eq. 89, with jacobian blocks:
654 // J_Vp_p = V: see V_helper, eq. 158
655 // J_Vp_theta: see fcn helper
656 // J_theta_theta = 1; eq. 126
657 _J_delta_tau.template topLeftCorner<2, 2>() = V_helper(tau(2));
658 _J_delta_tau.template topRightCorner<2, 1>() = J_Vp_theta(tau.template head<2>(), tau(2));
659 _J_delta_tau.template bottomRows<1>() << T(0), T(0), T(1);
660
661 exp(tau, _delta);
662}
663
664inline void exp(const VectorComposite& _tau, VectorComposite& _delta)
665{
666 _delta['P'].resize(2);
667 _delta['O'].resize(1);
668 exp(_tau.at('P'), _tau.at('O'), _delta['P'], _delta['O']);
669}
670
672{
673 VectorComposite res;
674 exp(tau, res);
675 return res;
676}
677
678// inline void exp(const VectorComposite& _tau, VectorComposite& _delta, MatrixComposite& _J_delta_tau)
679// {
680// // [1] eq. 156
681// const auto& p = _tau.at('P');
682// const auto& theta = pi2pi(_tau.at('O')(0));
683// Matrix2d V = V_helper(theta);
684
685// _delta['P'] = V * p;
686// _delta['O'] = Matrix1d(theta);
687
688// // Jacobian follows the composite definition in [1] eq. 89, with jacobian blocks:
689// // J_Vp_p = V: see V_helper, eq. 158
690// // J_Vp_theta: see fcn helper
691// // J_theta_theta = 1; eq. 126
692// _J_delta_tau.clear();
693// _J_delta_tau.emplace('P', 'P', V);
694// _J_delta_tau.emplace('P', 'O', J_Vp_theta(p, theta));
695// _J_delta_tau.emplace('O', 'P', RowVector2d(0.0, 0.0));
696// _J_delta_tau.emplace('O', 'O', Matrix1d(1));
697// }
698
700// LOG
701
702template <typename D1, typename D2>
703inline void log(const MatrixBase<D1>& p, const typename D1::Scalar& o, MatrixBase<D2>& rho, typename D2::Scalar& theta)
704{
707
708 typename D1::Scalar th = pi2pi(o);
709 rho = V_inv_helper(th) * p;
710 theta = th;
711}
712
713template <typename D1, typename D2, typename D3, typename D4>
714inline void log(const MatrixBase<D1>& p, const MatrixBase<D2>& o, MatrixBase<D3>& rho, MatrixBase<D4>& theta)
715{
718
719 log(p, o(0), rho, theta(0));
720}
721
722template <class D1, class D2>
723inline void log(const MatrixBase<D1>& _delta, MatrixBase<D2>& _tau)
724{
727
728 const auto p = _delta.template head<2>();
729 Map<Matrix<typename D2::Scalar, 2, 1>> rho(&_tau(0));
730
731 log(p, _delta(2), rho, _tau(2));
732}
733
734template <typename D>
735inline Matrix<typename D::Scalar, 3, 1> log(const MatrixBase<D>& _delta)
736{
737 Matrix<typename D::Scalar, 3, 1> _tau;
738 log(_delta, _tau);
739 return _tau;
740}
741
742template <class D1, class D2, class D3>
743inline void log(const MatrixBase<D1>& _delta, MatrixBase<D2>& _tau, MatrixBase<D3>& _J_tau_delta)
744{
747 MatrixSizeCheck<3, 3>::check(_J_tau_delta);
748
749 typedef typename D1::Scalar T;
750
751 Matrix<T, 3, 1> tau;
752 log(_delta, tau);
753
754 // inverse of the jacobian of exp(): J_exp = [V, J_Vp_theta; 0, 1] --> J_log = [V.inv, -V.inv * J_Vp_theta; 0, 1]
755 Matrix<T, 2, 2> V_inv = V_inv_helper(tau(2));
756
757 _J_tau_delta.template topLeftCorner<2, 2>() = V_inv;
758 _J_tau_delta.template topRightCorner<2, 1>() = -V_inv * J_Vp_theta(tau.template head<2>(), tau(2));
759 _J_tau_delta.template bottomRows<1>() << T(0), T(0), T(1);
760
761 _tau = tau;
762}
763
764inline void log(const VectorComposite& _delta, VectorComposite& _tau)
765{
766 _tau['P'].resize(2);
767 _tau['O'].resize(1);
768 log(_delta.at('P'), _delta.at('O'), _tau['P'], _tau['O']);
769}
770
772{
773 VectorComposite tau;
774 log(delta, tau);
775 return tau;
776}
777
779// PLUS (block-wise)
780
781template <typename D1, typename D2, typename D3>
782inline void plus(const MatrixBase<D1>& p1,
783 const typename D1::Scalar& o1,
784 const MatrixBase<D2>& p2,
785 const typename D2::Scalar& o2,
786 MatrixBase<D3>& plus_p,
787 typename D3::Scalar& plus_o)
788{
792
793 plus_p = p1 + p2;
794 plus_o = pi2pi(o1 + o2);
795}
796
797template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
798inline void plus(const MatrixBase<D1>& p1,
799 const MatrixBase<D2>& o1,
800 const MatrixBase<D4>& p2,
801 const MatrixBase<D5>& o2,
802 MatrixBase<D7>& plus_p,
803 MatrixBase<D8>& plus_o)
804{
808
809 plus(p1, o1(0), p2, o2(0), plus_p, plus_o(0));
810}
811
812template <typename D1, typename D2, typename D3>
813inline void plus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& d_plus)
814{
818
819 const auto p1 = d1.template head<2>();
820 const auto p2 = d2.template head<2>();
821 Map<Matrix<typename D3::Scalar, 2, 1>> p_p(&d_plus(0));
822
823 plus(p1, d1(2), p2, d2(2), p_p, d_plus(2));
824}
825
826template <typename D1, typename D2>
827inline Matrix<typename D1::Scalar, 3, 1> plus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
828{
829 Matrix<typename D1::Scalar, 3, 1> d_plus;
830 plus(d1, d2, d_plus);
831 return d_plus;
832}
833
834inline void plus(const VectorComposite& x, const VectorComposite& tau, VectorComposite& res)
835{
836 res['P'].resize(2);
837 res['O'].resize(1);
838 plus(x.at('P'), x.at('O'), tau.at('P'), tau.at('O'), res['P'], res['O']);
839}
840
842{
843 VectorComposite res;
844 plus(x, tau, res);
845 return res;
846}
847
849// MINUS (block-wise)
850
851template <typename D1, typename D2, typename D3>
852inline void minus(const MatrixBase<D1>& p1,
853 const typename D1::Scalar& o1,
854 const MatrixBase<D2>& p2,
855 const typename D2::Scalar& o2,
856 MatrixBase<D3>& pd,
857 typename D3::Scalar& od)
858{
862
863 pd = p2 - p1;
864 od = pi2pi(o2 - o1);
865}
866
867template <typename D1, typename D2, typename D3>
868inline void minus(const MatrixBase<D1>& p1,
869 const typename D1::Scalar& o1,
870 const MatrixBase<D2>& p2,
871 const typename D2::Scalar& o2,
872 MatrixBase<D3>& pd,
873 typename D3::Scalar& od,
874 typename D3::Scalar& J_do_o1,
875 typename D3::Scalar& J_do_o2)
876{
877 minus(p1, o1, p2, o2, pd, od);
878
879 J_do_o1 = typename D3::Scalar(-1);
880 J_do_o2 = typename D3::Scalar(1);
881}
882
883template <typename D1, typename D2, typename D4, typename D5, typename D7, typename D8>
884inline void minus(const MatrixBase<D1>& p1,
885 const MatrixBase<D2>& o1,
886 const MatrixBase<D4>& p2,
887 const MatrixBase<D5>& o2,
888 MatrixBase<D7>& pd,
889 MatrixBase<D8>& od)
890{
894
895 minus(p1, o1(0), p2, o2(0), pd, od(0));
896}
897
898template <typename D1, typename D2, typename D3>
899inline void minus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2, MatrixBase<D3>& err)
900{
904
905 const auto p1 = d1.template head<2>();
906 const auto p2 = d2.template head<2>();
907 Map<Matrix<typename D3::Scalar, 2, 1>> pd(&err(0));
908
909 minus(p1, d1(2), p2, d2(2), pd, err(2));
910}
911
912template <typename D1, typename D2, typename D3, typename D4, typename D5>
913inline void minus(const MatrixBase<D1>& d1,
914 const MatrixBase<D2>& d2,
915 MatrixBase<D3>& dif,
916 MatrixBase<D4>& J_diff_d1,
917 MatrixBase<D5>& J_diff_d2)
918{
921
922 minus(d1, d2, dif);
923
924 // block-wise difference: trivial jacobians
925 J_diff_d1 = -Matrix<typename D4::Scalar, 3, 3>::Identity();
926 J_diff_d2 = Matrix<typename D5::Scalar, 3, 3>::Identity();
927}
928
929template <typename D1, typename D2>
930inline Matrix<typename D1::Scalar, 3, 1> minus(const MatrixBase<D1>& d1, const MatrixBase<D2>& d2)
931{
932 Matrix<typename D1::Scalar, 3, 1> ret;
933 minus(d1, d2, ret);
934 return ret;
935}
936
937inline void minus(const VectorComposite& x1, const VectorComposite& x2, VectorComposite& res)
938{
939 res['P'].resize(2);
940 res['O'].resize(1);
941 minus(x1.at('P'), x1.at('O'), x2.at('P'), x2.at('O'), res['P'], res['O']);
942}
943
945{
946 VectorComposite res;
947 minus(x1, x2, res);
948 return res;
949}
950
952// INTERPOLATE
953
954template <typename D1, typename D2, typename D3>
955inline void interpolate(const MatrixBase<D1>& d1,
956 const MatrixBase<D2>& d2,
957 const typename D1::Scalar& t,
958 MatrixBase<D3>& ret)
959{
963
964 Matrix<typename D1::Scalar, 3, 1> dd = between(d1, d2);
965
966 Matrix<typename D1::Scalar, 3, 1> tau = t * log(dd);
967
968 ret = compose(d1, exp(tau));
969}
970
971template <typename D1, typename D2>
972inline Matrix<typename D1::Scalar, 3, 1> interpolate(const MatrixBase<D1>& d1,
973 const MatrixBase<D2>& d2,
974 const typename D1::Scalar& t)
975{
976 Matrix<typename D1::Scalar, 3, 1> ret;
977 interpolate(d1, d2, t, ret);
978 return ret;
979}
980
981inline void interpolate(const VectorComposite& x1, const VectorComposite& x2, const double& t, VectorComposite& res)
982{
983 VectorComposite tau = log(between(x1, x2));
984 tau['P'] *= t;
985 tau['O'] *= t;
986 compose(x1, exp(tau), res);
987}
988
989inline VectorComposite interpolate(const VectorComposite& x1, const VectorComposite& x2, const double& t)
990{
991 VectorComposite res;
992 interpolate(x1, x2, t, res);
993 return res;
994}
995
997// HOMOGENEOUS MATRIX
998
999template <typename D1, typename D2>
1000inline void toSE2(const MatrixBase<D1>& pose, MatrixBase<D2>& SE2)
1001{
1004
1005 typedef typename D1::Scalar T;
1006
1007 SE2.template block<2, 1>(0, 2) = pose.template head<2>();
1008 SE2.template block<2, 2>(0, 0) = SO2::exp(T(pose(2)));
1009 SE2.template block<1, 2>(2, 0).setZero();
1010 SE2(2, 2) = (T)1.0;
1011}
1012
1013template <typename D>
1014inline Matrix<typename D::Scalar, 3, 3> toSE2(const MatrixBase<D>& pose)
1015{
1016 Matrix<typename D::Scalar, 3, 3> SE2;
1017 toSE2(pose, SE2);
1018 return SE2;
1019}
1020
1021} // namespace SE2
1022} // namespace wolf
Definition: vector_composite.h:27
Namespace extending Eigen definitions.
Definition: wolf.h:94
const double EPS
Definition: wolf.h:74
Matrix< typename D::Scalar, 3, 3 > jac_SE2_left(const MatrixBase< D > &tangent)
Left Jacobian of SE(2), with tangent = [rho, theta]. See [1] eq. 164.
Definition: SE2.h:181
void identity(MatrixBase< D > &p, typename D::Scalar &o)
Definition: SE2.h:257
Matrix< T, 2, 2 > V_helper(const T theta)
V(theta) matrix, so that exp([rho, theta]) = [V(theta) * rho, theta]. See [1] eq. 158.
Definition: SE2.h:103
void exp(const MatrixBase< D1 > &rho, const typename D1::Scalar &theta, MatrixBase< D2 > &p, typename D2::Scalar &o)
Definition: SE2.h:603
void compose(const MatrixBase< D1 > &p1, const typename D1::Scalar &o1, const MatrixBase< D2 > &p2, const typename D2::Scalar &o2, MatrixBase< D3 > &pc, typename D3::Scalar &oc)
Definition: SE2.h:363
Matrix< typename D::Scalar, 3, 3 > jac_SE2_right_inv(const MatrixBase< D > &tangent)
Inverse of the right Jacobian of SE(2), with tangent = [rho, theta].
Definition: SE2.h:248
void log(const MatrixBase< D1 > &p, const typename D1::Scalar &o, MatrixBase< D2 > &rho, typename D2::Scalar &theta)
Definition: SE2.h:703
void between(const MatrixBase< D1 > &p1, const typename D1::Scalar &o1, const MatrixBase< D2 > &p2, const typename D2::Scalar &o2, MatrixBase< D3 > &p12, typename D3::Scalar &o12)
Definition: SE2.h:533
void toSE2(const MatrixBase< D1 > &pose, MatrixBase< D2 > &SE2)
Definition: SE2.h:1000
Matrix< typename D::Scalar, 3, 3 > jac_SE2_right(const MatrixBase< D > &tangent)
Right Jacobian of SE(2), with tangent = [rho, theta]. See [1] eq. 163.
Definition: SE2.h:224
void minus(const MatrixBase< D1 > &p1, const typename D1::Scalar &o1, const MatrixBase< D2 > &p2, const typename D2::Scalar &o2, MatrixBase< D3 > &pd, typename D3::Scalar &od)
Definition: SE2.h:852
void interpolate(const MatrixBase< D1 > &d1, const MatrixBase< D2 > &d2, const typename D1::Scalar &t, MatrixBase< D3 > &ret)
Definition: SE2.h:955
Matrix< typename D::Scalar, 3, 3 > jac_SE2_left_inv(const MatrixBase< D > &tangent)
Inverse of the left Jacobian of SE(2), with tangent = [rho, theta].
Definition: SE2.h:232
void inverse(const MatrixBase< D1 > &p, const typename D1::Scalar &o, MatrixBase< D2 > &ip, typename D2::Scalar &io)
Definition: SE2.h:307
Matrix< T, 2, 2 > skew(const T &t)
Definition: SE2.h:87
VectorComposite identityComposite()
Definition: SE2.h:296
Matrix< typename D::Scalar, 2, 1 > skewed(const MatrixBase< D > &t)
Compute [1]_x * t = (-t.y ; t.x)
Definition: SE2.h:95
Matrix< T, 2, 1 > J_Vp_theta(const MatrixBase< D > &p, const T theta)
Jacobian of V(theta)*p wrt theta.
Definition: SE2.h:145
Matrix< T, 2, 2 > V_inv_helper(const T theta)
Inverse of V(theta), so that log([p, theta]) = [V(theta).inv * p, theta].
Definition: SE2.h:129
void plus(const MatrixBase< D1 > &p1, const typename D1::Scalar &o1, const MatrixBase< D2 > &p2, const typename D2::Scalar &o2, MatrixBase< D3 > &plus_p, typename D3::Scalar &plus_o)
Definition: SE2.h:782
Matrix< T, 2, 2 > exp(const T theta)
Definition: SE2.h:75
Jet< T, N > abs(const Jet< T, N > &f)
Definition: jet.h:531
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:641
Jet< T, N > tan(const Jet< T, N > &f)
Definition: jet.h:656
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:626
Definition: capture_base.h:23
T pi2pi(const T &_angle)
Return angle between -pi and pi This implementation uses std::remainder which makes it incompatible f...
Definition: rotations.h:34
static void check(const Eigen::MatrixBase< T > &t)
Assert matrix size dynamically or statically.
Definition: eigen_assert.h:93